/**
* mpsvr工具类
* @author thinkry
*/

#ifndef __MPSVR_UTILS_H__
#define __MPSVR_UTILS_H__

#include "mpdef.h"
#include "net/CTSocket.h"
#include "CTBuffer.h"

class CMpUtils
{
public:
    enum
    {
        RET_RECV_ZERO_MSG = -100,
    };
    /**
    * 读取一个Code
    * @param[in] stSocket 要读取的socket
    * @param[in] stBuffer 保存读取的数据
    * @param[out] pszCodeBuf 这个Code在stBuffer的起始位置
    * @param[out] iCodeLen 这个Code的长度, 0表示没有Code没有接收完全 -1表示收到0字节的消息(表示退出)
    * @return 0表示成功 可能还会返回CT_EINPROGRESS CT_EWOULDBLOCK CT_ETIME CT_ECONNRESET
    */
    static int RecvOneCode(CTSocket& stSocket,
                           CTBuffer& stBuffer,
                           char*& pszCodeBuf,
                           int& iCodeLen)
    {
        pszCodeBuf = NULL;
        iCodeLen = 0;

        int iRet = 0;
        int iRecvLen = 0;

        if (stBuffer.GetUsedLen() > 0)
        {
            CT_WARNING(("RecvOneCode used buffer has %d bytes", stBuffer.GetUsedLen()));
        }

        // stBuffer.GetFreeLen() - 1 预留一个字节, 存放'\0'
        iRet = stSocket.Recv(stBuffer.GetFreeBuf(), stBuffer.GetFreeLen() - 1, iRecvLen);
        if (iRet)
        {
            return iRet;
        }

        stBuffer.Append(iRecvLen);

        int iMsgLen = ntohl(*(int*)stBuffer.GetUsedBuf());
        if (iMsgLen == 0)
        {
            pszCodeBuf = NULL;
            stBuffer.Remove(sizeof(iMsgLen));
            return RET_RECV_ZERO_MSG;
        }

        // 注意这里移动后, 字符串协议就不是以\0结尾了
        stBuffer.Remove(sizeof(iMsgLen));

        // 在最后加个'\0'
        // 对二进制协议没有用, 对字符串协议来说, 需要有\0结尾来
        *(char*)(stBuffer.GetUsedBuf() + stBuffer.GetUsedLen()) = '\0';

        if (iMsgLen > stBuffer.GetUsedLen()) // 消息没收完
        {
            pszCodeBuf = NULL;
            iCodeLen = 0;
        }
        else if (iMsgLen == stBuffer.GetUsedLen())
        {
            pszCodeBuf = stBuffer.GetUsedBuf();
            iCodeLen = iMsgLen;
        }
        else
        {
            pszCodeBuf = stBuffer.GetUsedBuf();
            iCodeLen = iMsgLen;

            // 还有预留的数据, 不太合理
            CT_WARNING(("remain data. stBuffer.GetUsedLen()=%d iMsgLen=%d",
                stBuffer.GetUsedLen(), iMsgLen));
        }

        return 0;
    }
};

#endif //__MPSVR_UTILS_H__
